home *** CD-ROM | disk | FTP | other *** search
- /*
- File: PAPServerSample.c
-
- Contains: This sample demonstrates the implementation of a PAP server using Open Transport.
-
- Issues:
- 1. PostScript Query responses are default only
- To respond to the LaserWriter client, the PostScript query handler code is
- designed to return the default responses. A real PAP spooler would have to
- respond more appropriately for the printer that it is supporting. This could mean
- delaying the response back to the client until the spooler can actually
- pass the query to the printer and get a real response. The code for detecting
- a PostScript query is not very robust. The purpose of this sample was not to
- demonstrate PostScript support, but to packet flow via OT.
-
- 2. If the received data is not part of a PostScript query, the spooler sample
- assumes that all of the incoming data is part of the same job. There is no check
- for the PostScript EOF indicator to distinguish different spooler jobs. All of the
- incoming data is saved to a temporary disk file at the root of the boot hard drive.
- The code does not try to preflight the amount of storage present, nor protect
- some minimum hard drive storage in case the hard drive is close to full.
-
- 3. This sample requires OT 1.1.2 or greater.
-
- 4. This sample support multiple handoff endpoints. The constant kMaxHandoffEPs
- defines the maximum number of handoff endpoints that this sample supports. I have
- tested that the server supports 2 endpoint connections at the same time, but have not
- gone into testing more simultaneous connections.
-
- Written by: Rich Kubota
-
- Copyright: Copyright © 1999 by Apple Computer, Inc., All Rights Reserved.
-
- You may incorporate this Apple sample source code into your program(s) without
- restriction. This Apple sample source code has been provided "AS IS" and the
- responsibility for its operation is yours. You are not permitted to redistribute
- this Apple sample source code as "Apple sample source code" after having made
- changes. If you're going to re-distribute the source, we require that you make
- it clear in the source that the code was descended from Apple sample source
- code, but that you've made changes.
-
- Change History (most recent first):
- 7/22/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1
-
-
- */
- #define HANDOFF_EP 1 // set to to to indicate use of handoff endpoint
- #include <GestaltEqu.h>
- #include <TextUtils.h>
- #include <DiskInit.h>
- #include <Types.h>
- #include <Errors.h>
- #include <String.h>
- #include <ToolUtils.h>
- #include "StringUtils.h"
- #include <AppleTalk.h>
- #include "OpenTransport.h"
- #include "OpenTptAppleTalk.h"
- #include "ATalkSampleUtils.h"
- #include "PAPServerUtilities.h"
- #include "PAPServerSample.h"
- #include "PAPPostScriptStuff.h"
- extern OSStatus OTSetMemoryLimits(size_t growSize, size_t maxSize);
-
- /********************/
- /* globals */
- /********************/
- DDPAddress gAddr;
- MyEndpointRef gEp;
-
- #if HANDOFF_EP
- MyEndpointRef gHandoffEp[kMaxHandoffEPs];
- #endif
-
- OTLIFO* gFreeQ; // note that an OTLIFO structure must be on a 4-byte boundary
- // instead of trying to force it to be on a 4-byte boundary in
- // global memory, we use a pointer, then allocate memory
- // which will force the global to be on a 4-byte boundary.
- UInt32 gFlags = 0;
- UInt32 gBufsAvail;
- PacketPtr gTempPackPtr;
- short gFRefNumToClose = 0;
- Boolean gDone = false;
- Str255 gIdleStr;
- Str255 gBusyStr;
- Str255 gServerNBPNameStr;
- UInt32 gOptionCompleted; // used to flag completion of Option Management calls
- extern char gEOFStr[8];
- extern char gBeginPSStr[8];
- extern char qBeginQueryStr[8];
- extern char gEndStr[8];
- extern char gQueryStr[8];
-
- OSType gOTVersionSelector = 'otvr';
- UInt32 gOTVersion;
-
-
- /*******************************************************************************
- ** Prototypes
- ********************************************************************************/
-
- pascal void EventHandler(void*, OTEventCode, OTResult, void*);
- static void EnterListenAccept(MyEndpointRef *myServerEp);
- void DoListenAccept(MyEndpointRef *myServerEp);
- Boolean ReceiveOnePacket(MyEndpointRef *myEp, PacketPtr packetPtr);
- void DoReceiveData(MyEndpointRef *myEp);
- OSStatus DoDisconnect(MyEndpointRef *myEp);
- OSStatus DoOrderlyDisconnect(MyEndpointRef *myEp);
- OSStatus PollQueueList(void);
- OSErr ProcessIncomingDataFile(MyEndpointRef *theEp, PacketPtr packetPtr);
- Boolean TestDataIsPSQuery(PacketPtr packetPtr);
- OSStatus ProcessPSQuery(PacketPtr packetPtr);
- Boolean DoProcessPSQuery(PacketPtr packetPtr);
- OSErr CheckFileToClose(void);
- void DoServer(void);
- void DoEvent(EventRecord *event);
- OSStatus DoBind(EndpointRef ep, UInt8 socket, UInt8 type, OTQLen qlen,
- char *nbpName, UInt32 nbpNameLen);
- OSStatus ActivatePAPEndpoint(MyEndpointRef *myEp);
- OSStatus InitPAPServerStuff(void);
- void ClosePAPServerStuff(void);
- OSStatus InitMyEndpointRef(MyEndpointRef *myEp);
- OSStatus InitPAPBuffers(void);
- void ReleasePAPMemory(void);
- extern OSStatus DoNegotiateEOMOption(EndpointRef ep, Boolean enableEOM);
- extern OSStatus DoSetServerStatusOption(EndpointRef ep, char *statusStr);
- extern OSStatus DoNegotiateSelfSendOption(EndpointRef ep, long enableSelfSend);
- void DoValueBreak(long value, const char* message);
- OSStatus BeginSetServerStatusOption(EndpointRef ep, UInt16 whichStr);
- UInt32 GetYesNoOption(void);
- Boolean EndpointsAllBusy(void);
- #if HANDOFF_EP
- MyEndpointRef* FindFreeHandoffEp(void);
- #endif
-
- /*******************************************************************************
- ** EventHandler
- ** The event handler can be called at times when it is not safe to do console I/O,
- ** so this routine takes the event and jams it on a list to be handled when
- ** we know it's safe to print informative messages
- ********************************************************************************/
-
- pascal void EventHandler(void* contextPtr, OTEventCode code,
- OTResult result, void* cookie)
- {
- #pragma unused(result,cookie)
- switch (code)
- {
- case T_LISTEN: /* An connection request is available */
- SetListenPendFlag(((MyEndpointRef*)contextPtr)->flags);
- DoListenAccept(contextPtr);
- break;
-
- // T_DATA:
- //
- // The main rule for processing T_DATA's is to remember that once you have
- // a T_DATA, you won't get another one until you have read to a kOTNoDataErr.
- // The advanced rule is to remember that you could get another T_DATA
- // during an OTRcv() which will eventually return kOTNoDataErr, presenting
- // the application with a synchronization issue to be most careful about.
- //
- // In this application, since an OTRcv() calls are made from inside the notifier,
- // this particular synchronization issue doesn't become a problem.
- //
- case T_DATA: /* Standard data is available */
- // check that we are in the DATAXFER state
- SetHasDataFlag(((MyEndpointRef*)contextPtr)->flags);
- if (TstPassconFlag(((MyEndpointRef*)contextPtr)->flags))
- DoReceiveData(contextPtr);
- break;
-
- case T_DISCONNECT: /* A disconnect is available */
- // check whether there is a file open on this endpoint
- DoDisconnect(contextPtr);
- break;
-
- case T_ERROR: /* obsolete/unused in library */
- case T_UDERR: /* A Unit Data Error has occurred */
- #if SHOW_DEBUG_FLOW
- DebugStr((const unsigned char *)"\p T_ERROR called;g");
- #endif
- break;
-
- case T_ORDREL: /* An orderly release is available */
- DoOrderlyDisconnect(contextPtr);
- break;
-
- case T_GODATA: /* Flow control lifted on standard data */
- // for this sample, I do not expect this event to occur.
- #if SHOW_DEBUG_FLOW
- DebugStr((const unsigned char *)"\p T_GODATA called;g");
- #endif
- break;
-
- case T_GOEXDATA: /* Flow control lifted on expedited data*/
- // for this sample, I do not expect this event to occur.
- #if SHOW_DEBUG_FLOW
- DebugStr((const unsigned char *)"\p T_GOEXDATA called;g");
- #endif
- break;
-
- case T_PASSCON: /* State is now case T_DATAXFER */
- // set the passcon flag
- // set flag to indicate that the endpoint is busy
- SetEPBusyFlag(((MyEndpointRef*)contextPtr)->flags);
- // set flag to teel system to set server status flag appropriately
- // for multiple handoff endpoint servers, this would need to be
- // handled differently.
- SetCheckOptFlag(gFlags);
-
- SetPassconFlag(((MyEndpointRef*)contextPtr)->flags);
-
- // Set the timer for this connection
- OTGetTimeStamp(&((MyEndpointRef*)contextPtr)->timerDog);
-
- // check to see if there is any data to process
- DoReceiveData(contextPtr);
- break;
-
- case T_RESET: /* Protocol has been reset */
- #if SHOW_DEBUG_FLOW
- DebugStr("\p T_RESET called;g");
- #endif
- break;
-
- case T_ACCEPTCOMPLETE: /* Accept call is complete */
- #if SHOW_DEBUG_FLOW
- DebugStr("\p T_ACCEPTCOMPLETE called;g");
- #endif
- ClrAcceptPendFlag(((MyEndpointRef*)contextPtr)->flags);
- break;
-
- case T_DISCONNECTCOMPLETE: /* Disconnect call is complete */
- break;
-
- case T_UNBINDCOMPLETE:
- #if SHOW_DEBUG_FLOW
- DebugStr("\p T_UNBINDCOMPLETE called;g");
- #endif
- SetCheckOptFlag(gFlags);
- ClrEPBusyFlag(((MyEndpointRef*)contextPtr)->flags);
-
- SetStatusIdleFlag(gFlags);
-
- ClrEPBoundFlag(((MyEndpointRef*)contextPtr)->flags); // is the server endpoint bound
- break;
-
- //
- // kStreamIoctlEvent:
- //
- // This event is returned when an I_FLUSH ioctl has completed.
- // The flush was done in an attempt to get back all T_MEMORYRELEASED events
- // for outstanding OTSnd() calls with Ack Sends. Errors are ignored at this point since it is
- // possible that the connection will already be gone, etc.
- //
- case kStreamIoctlEvent:
- return;
- break;
-
- case T_OPTMGMTCOMPLETE:
- gOptionCompleted = 1;
- break;
-
- default:
- break;
- }
- }
-
- //
- // EnterListenAccept
- //
- // This is a front end to DoListenAccept() which is used whenever
- // it is not being called from inside the listener endpoint's notifier.
- // We do this for syncrhonization. If we were processing an OTListen()
- // or an OTAccept() and we were interrupted at the listener endpoint's
- // notifier with a T_LISTEN, etc, it would be inconvenient and would require
- // some more sophisticated synchronization code to deal with the problem.
- // The easy way to avoid this is to do an OTEnterNotifier() on the listener's
- // endpoint.
- //
- // Important note - doing OTEnterNotifier on one endpoint only prevents that
- // endpoint's notifier for interrupting us. Since the same notifier code
- // is used for lots of endpoints here, remember that the one endpoint's
- // notifier can interrupt another. Doing an OTEnterNotifier() on the
- // listener endpoint prevents the listener from interrupting us, but it
- // does not prevent the Notifier() routine from interrupting us via
- // another endpoint which also uses the same routine.
- //
- // Important note #2 - Don't ever do an OTEnterNotifier on an acceptor endpoint
- // before doing the OTAccept(). This confuses OT and creates problems.
- //
- static void EnterListenAccept(MyEndpointRef *myServerEp)
- {
- Boolean doLeave;
-
- doLeave = OTEnterNotifier(myServerEp->ep);
- DoListenAccept(myServerEp);
- if (doLeave)
- OTLeaveNotifier(myServerEp->ep);
- }
-
- /*
- DoListenAccept is designed to handle an incoming connect request. This module demonstrates a
- very complex task that all X/OPEN style acceptors must implement. The problem stems from
- fact that an endpoint may be hit by a number of simultaneous connect requests. In addition
- if there is a connection already established and the endpoint handles multiple
- handoff endpoints, then there could also be an incoming disconnect request to process before
- one can issue either an Accept or Disconnect response, all pending Connect requests must
- be consumed from the streamhead first. This places a burden on the accept routine to have
- a place to temporarily stash all of the addresses to which discon messages will have to be
- sent.
-
- Refer to Tech Note 1059 for the 8 steps to handling an incoming connection request.
-
- Note that once all of the connect request have been consumed and we are in the process of
- sending discon responses, it could be that there will again be an kOTLookErr, which
- indicates that another incoming connect request heeds to be consumed before
- resuming with the discon responses.
-
- In this sample we consume the first listen request. We then check whether we can accept
- the incoming request, If so, then call OTAccept. If OTAccept fails with a lookErr, then
- there is another connect request to be consumed.
-
- processed.
-
- */
- void DoListenAccept(MyEndpointRef *myServerEp)
- {
- MyEndpointRef *myAcceptEp;
- OSStatus err;
- TDiscon discon;
- OTResult result;
- TCall call;
- Boolean done = false;
-
- // check we have already entered DoListenAccept from the main event loop and are
- // trying to do so again from the secondary interrupt
- if (OTAtomicSetBit(&myServerEp->semaphore, kInListenLoop))
- return; // if the bit was previous set, then we already have entered, but not exitted
- // this proc from the main event loop
-
- if (TstAcceptPendFlag(myServerEp->flags))
- {
- // we're waiting for an Accept call to complete, so don't accept a new
- // connection request as we will get an out of state error
- // set the ListenPendFlag so we will check the server endpoint later
-
- SetListenPendFlag(myServerEp->flags);
- done = true;
- }
- else
- ClrListenPendFlag(myServerEp->flags);
-
- if (done == false)
- {
- // clear out the TCall structure
- memset(&call, 0, sizeof(TCall));
-
- // set up the TCall structure
- call.addr.maxlen = sizeof(struct DDPAddress);
- call.addr.len = sizeof(struct DDPAddress);
- call.addr.buf = (unsigned char *) &gAddr;
-
- if (OTIsSynchronous(myServerEp->ep) == true)
- OTSetAsynchronous(myServerEp->ep);
-
- // step 1 for handling an incoming connection request
- err = OTListen(myServerEp->ep, &call);
-
- if (err == kOTNoDataErr)
- {
- #if SHOW_DEBUG_FLOW
- DebugStr("\p kOTNoDataErr returned by OTListen");
- #endif
- // don't need to do anything
- }
- else if (err == kOTLookErr)
- {
- // step 2 for handling incoming connection requests
- // handle disconnect indications for a pending connection request
- // the only look indication allowed on an OTListen call is
- // T_DISCONNECT
- result = OTLook(myServerEp->ep);
- if (result == T_DISCONNECT)
- {
- // this is what we were expecting
- // the disconnect is for an outstanding listen request
- err = OTRcvDisconnect(myServerEp->ep, &discon);
-
- }
- else
- {
- #if SHOW_DEBUG_FLOW
- DebugStr((const unsigned char *)"\p unknown event returned by OTLook");
- #endif
- }
- done = true;
-
- }
- else if (err != kOTNoError) // there was an unknown error in doing the listen
- {
- DoValueBreak((long)err, "error occured on OTListen #");
- done = true;
-
- }
- }
-
- if (done == false)
- {
- #if HANDOFF_EP
- myAcceptEp = FindFreeHandoffEp();
- #else
- if (TstEPBusyFlag(myServerEp.flags) == false)
- myAcceptEp = myServerEp;
- else
- myAcceptEp = nil;
- #endif
- }
-
- if (myAcceptEp == nil)
- {
- // if there are no available handoff endpoints, then send the disconnect
- OTSndDisconnect(myServerEp->ep, &call);
- done = true;
- }
-
- if (done == false)
- {
-
- // set a flag to indicate that an accept call is pending
- // if we try to accept another connection before this
- // accept call is completed, an out of state error results
- // need to do this before we make the OTAccept call
- SetAcceptPendFlag(myServerEp->flags);
-
- // make the accept call and handoff the connection
- err = OTAccept(myServerEp->ep, myAcceptEp->ep, &call);
-
- #if SHOW_DEBUG_FLOW
- DoValueBreak((long)err, "OTAccept returned #");
- #endif
-
- if (err == kOTNoError)
- {
- SetEPBusyFlag(myAcceptEp->flags);
-
- // set flag to have server check the serverstatus
- TstCheckOptFlag(gFlags);
-
- }
- else if (err == kOTLookErr)
- {
- // an OTLookErr for an OTAccept call means that there is
- // either an T_LISTEN or T_DISCONNECT event
-
- // check what event is on the pipe
- result = OTLook(myServerEp->ep);
- if (result == T_DISCONNECT)
- {
- err = OTRcvDisconnect(myServerEp->ep, &discon);
-
- }
-
- }
- else
- {
- #if HANDOFF_EP
- DoValueBreak((long)err, "error occured on OTAccept for handoff #");
- #else
- DoValueBreak((long)err, "error occured on OTAccept #");
- #endif
-
- }
- }
-
-
- OTAtomicClearBit(&myServerEp->semaphore, kInListenLoop); // clear the bit that indicates we're in this loop
-
- }
-
- /*******************************************************************************
- ** ReceiveOnePacket - makes the call to receive just one packet
- ** If there is data, then the data is placed into the packetPtr
- ** and the incoming byte count is incremented
- ** if the kOTNoDataErr occurs, then the HasDataFlag is cleared.
- **
- **
- ********************************************************************************/
- Boolean ReceiveOnePacket(MyEndpointRef *myEp, PacketPtr packetPtr)
- {
- UInt32 localFlag = 0;
- OTResult result, res;
- Boolean done = false;
-
- result = OTRcv(myEp->ep, &packetPtr->data, kPAPDataSize, &packetPtr->flags);
- if (result < 0)
- {
- // requeue the buffer to the freeq
- OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));
- done = true;
-
- if (result == kOTLookErr)
- {
- res = OTLook(myEp->ep);
- // for an OTRcv call, there are only 2 OTLook responses
- if (res == T_DISCONNECT)
- {
- res = DoDisconnect(myEp->ep);
- // if we get a disconnect event, then there will be no more
- // data in the pipe.
- #if SHOW_DEBUG_FLOW
- DebugStr("\p processing disconnect in OTRcv;g");
- #endif
- ClrOrdDisconFlag(myEp->flags);
- ClrInPSQueryFlag(myEp->flags);
- }
- else if (res == T_ORDREL)
- {
- #if SHOW_DEBUG_FLOW
- DebugStr("\p processing orderly disconnect in OTRcv;g");
- #endif
- res = DoOrderlyDisconnect(myEp->ep);
- localFlag = 1;
- }
-
- }
- else if (result == kOTOutStateErr)
- {
- // client could have issued a disconnect call while this call was about to
- // to be processed
- ClrHasDataFlag(myEp->flags);
- }
-
- else if (result == kOTNoDataErr)
- {
- // no more data so clr the flag
- ClrHasDataFlag(myEp->flags);
- }
- else
- {
- #if SHOW_DEBUG_FLOW
- DebugStr("\pUnknown error occurred in OTRcv");
- #endif
- }
- }
- else if (result == 0)
- {
- #if SHOW_DEBUG_FLOW
- DebugStr("\p OTRcv got nothing ;g");
- #endif
-
- if (TstInPSQueryFlag(myEp->flags)) // check if the endpoint is already processing a postscript
- {
- #if SHOW_DEBUG_FLOW
- DebugStr("\p 0 byte packet while processing ps query ;g");
- #endif
- #if SHOW_DEBUG_FLOW
- if (packetPtr->flags & T_MORE == 0)
- DebugStr("\p T_MORE was not set;g");
- else
- DebugStr("\p T_MORE was set;g");
- #endif
- // send an empty response with EOF flasg set since it appears that this is what the Laserwriter
- // client wants to see.
- packetPtr->theEp = myEp;
- SendEmptyPacket(packetPtr);
- // clear bit that indicates we are processing a postscript query
- ClrInPSQueryFlag(myEp->flags);
- #if SHOW_DEBUG_FLOW
-
- DebugStr("\p Have finished ps query;g");
- #endif
- }
-
- // requeue the buffer to the freeq since no data was returned
- OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));
- }
- else
- {
-
- if (TstdumpPktsFlag(gFlags))
- {
- OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));
- }
- else
- {
-
- // save the endpoint ref associated with this data
- packetPtr->theEp = myEp;
-
- // save the number of bytes read
- packetPtr->numBytes = result;
-
- // intialize the lastPos field
- packetPtr->lastPos = 0;
-
- // get the timestamp for this packet
- OTGetTimeStamp(&packetPtr->timeStamp);
-
- // Set the timer for this connection
- OTGetTimeStamp(&myEp->timerDog);
-
- if (!DoProcessPSQuery(packetPtr))
- {
- // packet is not a postscript query so queue to the endpoint usedQ
- // queue the buffer to the usedQ associated with the endpoint
- OTLIFOEnqueue(myEp->usedQ, &(packetPtr->fLink));
-
- }
-
- }
-
- }
-
- return done;
-
- }
-
-
- /*******************************************************************************
- ** DoReceiveData
- **
- ********************************************************************************/
- void DoReceiveData(MyEndpointRef *myEp)
- {
- PacketPtr packetPtr;
- OTFlags flags = 0;
- UInt32 localFlag = 0;
- Boolean done;
-
- // check we have already entered DoReceiveData from the main event loop
- // or from the event handler and are
- // trying to do so again a second time
- if (OTAtomicSetBit(&myEp->semaphore, kInRcvDataFlag))
- return; // if the bit was previous set, then we already have entered, but not exitted
- // this proc from the main event loop
-
- done = gDone;
- while (done == false)
- {
- if (gFreeQ->fHead != nil)
- {
- packetPtr = (PacketPtr)OTLIFODequeue(gFreeQ);
- done = ReceiveOnePacket(myEp, packetPtr);
- }
- else
- {
-
- done = true;
- }
-
-
- }
-
- OTAtomicClearBit(&myEp->semaphore, kInRcvDataFlag);
- // clear the bit that indicates we're in this loop
-
- }
-
-
- OSStatus DoDisconnect(MyEndpointRef *myEp)
- {
- OSStatus err;
-
-
- err = OTRcvDisconnect(myEp->ep, NULL);
- if (err != kOTNoError)
- {
- #if SHOW_DEBUG_FLOW
- DoValueBreak((long)err, "error occured on OTRcvDisconnect #");
- #endif
- }
- else
- {
- if (TstAcceptPendFlag(myEp->flags))
- ClrAcceptPendFlag(myEp->flags);
- }
-
- return err;
- }
-
- OSStatus DoOrderlyDisconnect(MyEndpointRef *myEp)
- {
- OSStatus err;
-
- err = OTRcvOrderlyDisconnect(myEp->ep);
- if (err < kOTNoError)
- {
- #if SHOW_DEBUG_FLOW
- DoValueBreak((long)err, "error occured on OTRcvOrderlyDisconnect #");
- #endif
- }
- else if (err > 0)
- {
- #if SHOW_DEBUG_FLOW
- DebugStr("\p OTRcvOrderlyDisconnect returned positive result;g");
- #endif
- SetOrdDisconFlag(myEp->flags);
- }
- else
- {
- SetOrdDisconFlag(myEp->flags);
- }
-
- return err;
- }
-
- /*******************************************************************************
- ** PollEventList
- ** This routine checks the used queue to see whether the handler has processed
- incoming PAP data from the client.
- ** If the used queue is not empty, there are two different options to deal with.
- First we check whether we are in the middle of processing a postscript data
- file. If so, we continue to read the data into a file which we have created.
- If not currently processing postscript data, we then check to see if the incoming
- packet is part of a postscript query in progress or is the beginning of a
- postscript query. If so, we continue to read the query and respond as appropriate.
- If not a query, then this must be the first packet of postscript data being sent.
- ********************************************************************************/
-
- OSStatus PollQueueList(void)
- {
- PacketPtr packetPtr, nextPacketPtr;
- MyEndpointRef *theEp;
- OSStatus err = kOTNoError;
- short i = 0;
- Boolean done = false;
-
- #if SHOW_DEBUG_FLOW
- short num = 0;
- Boolean inLoop = false;
- #endif
-
- #if HANDOFF_EP
- for (i = 0; (i < kMaxHandoffEPs) && (err == kOTNoError); i++)
- {
- theEp = &gHandoffEp[i];
- #else
- theEp = &gEp;
- #endif
-
- packetPtr = (PacketPtr)OTLIFOStealList(theEp->usedQ);
- while (packetPtr != nil)
- {
-
- #if SHOW_DEBUG_FLOW
- inLoop = true;
- #endif
- packetPtr = (PacketPtr)OTReverseList((OTLink*)packetPtr);
- do
- {
- #if SHOW_DEBUG_FLOW
- num++;
- #endif
- nextPacketPtr = (PacketPtr)packetPtr->fLink.fNext;
-
- err = ProcessIncomingDataFile(theEp, packetPtr);
-
- // queue the packetPtr back to the freeQ
- OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink));
-
- packetPtr = nextPacketPtr;
-
- } while((packetPtr != nil) && (err == kOTNoError));
-
- packetPtr = (PacketPtr)OTLIFOStealList(theEp->usedQ);
- }
-
- #if HANDOFF_EP
- }
- #endif
-
- #if SHOW_DEBUG_FLOW
- if (inLoop)
- {
- // fprintf(stdout, "numbers packets processed by PollQueueList %d\n", num);
- }
- #endif
-
- return err;
- }
-
- OSErr ProcessIncomingDataFile(MyEndpointRef *theEp, PacketPtr packetPtr)
- {
- OSStatus err = noErr;
- short fRefNum;
-
-
- // For each incoming packet, we need to check whether it
- // contains postscript query requests, or if we have not yet
- // received the EOF
-
- if (!TstdumpPktsFlag(gFlags)) // check if we are dumping the packets
- {
- if (!TstTempFileFlag(theEp->flags)) // is there a temp file opened for this endpoint
- {
- // no, so create one
- err = OpenTempFile(&fRefNum);
- if (err == noErr)
- {
- fprintf(stdout, "processing incoming file\n");
- theEp->fRefNum = fRefNum; // save the refnum of the temp file;
- SetTempFileFlag(theEp->flags); // indicate that there is a temp file associated
- // with this endpoint.
- // set the time Data In timestamp field
- BlockMove((Ptr)&packetPtr->timeStamp, (Ptr)&theEp->timeDataIn, sizeof(OTTimeStamp));
- // reset the numBytesIn field to zero
- theEp->numBytesIn = 0;
- }
-
- }
- }
-
-
- if (err == noErr)
- {
-
- if (!TstdumpPktsFlag(gFlags)) // check if we are dumping the packets
- {
- // the temp file has been created or already exists, so read the data and write it
- // to the temp file
- err = WriteDataToTempFile(theEp->fRefNum, packetPtr->data, packetPtr->numBytes);
- }
-
- if (err != noErr)
- {
- #if SHOW_DEBUG_FLOW
- DoValueBreak((long)err, "error occured writing data to tempfile #");
- #endif
- }
- else
- {
- // set the time data end timestamp field
- BlockMove((Ptr)&packetPtr->timeStamp, (Ptr)&theEp->timeDataEnd, sizeof(OTTimeStamp));
- // add the number of bytes in the packet to the numBytesIn field
- theEp->numBytesIn += packetPtr->numBytes;
-
- // check if we've read the last packet for the file
- if ((packetPtr->flags & T_MORE) == 0)
- {
- if (!TstdumpPktsFlag(gFlags))
- {
- fprintf(stdout, "T_MORE flag not set \n");
-
- // the proper way to detect the end of a file is to look for
- // the EOF flag at the end of the file.
- // It also appears that looking for the T_MORE flag to be clear
- // is not a reliable way to detect the end of a file.
- // When a status request is sent by the client that is sending
- // data, the T_MORE flag appears to be cleared for the incoming
- // packet.
- }
-
- }
-
- }
- }
-
- return err;
- }
-
-
-
-
- OSErr CheckFileToClose(void)
- {
- OSErr err = noErr;
-
- if (gFRefNumToClose != 0)
- {
- fprintf(stdout, "\n\nAm about to close file with fRefNum %ld.\n", gFRefNumToClose);
-
- err = CloseTempFile(gFRefNumToClose);
- if (err != noErr)
- fprintf(stdout, "\n\nError occurred closing file - error %ld.\n", err);
-
- // reset the tempfile to close so that we don't close this file again
- gFRefNumToClose = 0;
- }
-
- return err;
- }
-
-
- /*******************************************************************************
- ** DoServer
- ********************************************************************************/
-
- void DoServer(void)
- {
- EventRecord theEvent;
- OTTimeStamp eTime;
- OTResult state;
- UInt32 eTimeMSec, sec, msec, rate;
- MyEndpointRef *theEp;
- OSStatus err1, err = kOTNoError;
- #if HANDOFF_EP
- short i = 0;
- #endif
-
- while (gDone == false)
- {
- if (!WaitNextEvent(everyEvent, &theEvent, 15, nil))
- theEvent.what = nullEvent;
-
- DoEvent(&theEvent);
-
- if (TstListenPendFlag(gEp.flags)) // are there incoming connect requests to process
- {
- fprintf(stdout, "\n processing EnterListenAccept from even tloop");
- EnterListenAccept(&gEp);
- }
-
- err = PollQueueList();
- if (err != kOTNoError) // we're outta here if an error occurred.
- gDone = true;
-
- #if HANDOFF_EP
- theEp = &gHandoffEp[i];
- i++;
- if (i >= kMaxHandoffEPs)
- i = 0;
- #else
- theEp = &gEp;
- #endif
- // get the current endpoint state
- state = OTGetEndpointState(theEp->ep);
-
- switch (state)
- {
- case T_DATAXFER:
-
- // check if we haven't completed reading data from OT.
- DoReceiveData(theEp);
- break;
-
- case T_INREL: // we've processed an incoming Orderly Release request
- // but have not issued our own orderly disconnect
-
-
- // note that since we have already processed an incoming orderly disconnect
- // we are in the INREL state. After making the OTSndOrderlyDisconnect
- // call, there will not be a T_DISCONNECTCOMPLETE call, since we complete
- // the orderly release with the above call. We go ahead and reset our flags
- // and issue the OTUnbind call if we are using a handoff endpoint.
- // if we did get the orderly release indication, then make sure we have
- // drained the receive queue - PollQueueList does this
-
- do
- {
- fprintf(stdout, "processing some last data\n");
- PollQueueList();
-
- // check if we haven't completed reading data from OT.
- DoReceiveData(theEp);
-
- }while( (TstHasDataFlag(theEp->flags)) || (theEp->usedQ->fHead != nil));
-
- // clear the flag and send a corresponding disconnect
- err = OTSndOrderlyDisconnect(theEp->ep);
- if (err)
- {
- // the only error that makes sense here is the kOTLookErr
- // which the only event is the T_DISCONNECT event. This should not happen,
- // however, if there are multiple handoffs, this may be an issue. Given the way
- // incoming requests are handled, I don't expect that there would be an
- // unresponded listen request here that would warrant a possible T_DISCONNECT
- // however some implementation will need to consider this possibility.
- #if SHOW_DEBUG_FLOW
- DoValueBreak((long)err, "error occured on OTSndOrderlyDisconnect #");
-
- DebugStr("\p quitting program");
- #endif
- gDone = true;
-
- }
-
- ClrOrdDisconFlag(theEp->flags);
-
- if (TstTempFileFlag(theEp->flags))
- {
- // is there an open spool file associated with this endpoint
- gFRefNumToClose = theEp->fRefNum; // set the global to have this file closed
- // note that this method of signalling for a file to
- // get closed is a quick and dirty method and assumes th
- // that only one file at a time is being processed here.
- CheckFileToClose();
- }
-
- ClrTempFileFlag(theEp->flags);
- ClrPassconFlag(theEp->flags);
-
- #if HANDOFF_EP
- // in order to re-use a handoff endpoint, it must be unbound. Unbinding the
- // endpoint clears the connection information that allows to to know which
- // endpoint, incoming PAP data is routed to.
- if (theEp->ep != gEp.ep)
- {
- OTUnbind(theEp->ep);
-
- }
- #else
- // indicate that we are no longer busy
- ClrEPBusyFlag(theEp->flags);
- // set flag so that we will check the status
- SetCheckOptFlag(gFlags);
- SetStatusIdleFlag(gFlags);
-
- #endif
-
-
- // calculate the elapsed time
- OTSubtractTimeStamps(&eTime, &theEp->timeDataIn, &theEp->timeDataEnd);
- // convert to millisecs
- eTimeMSec = OTTimeStampInMilliseconds(&eTime);
- sec = eTimeMSec / (UInt32)1000;
- msec = eTimeMSec %(UInt32)1000;
- fprintf(stdout, "Time to transfer file was %ld.%ld seconds.\n", sec, msec);
- fprintf(stdout, "Bytes transferred was - %ld.\n", theEp->numBytesIn);
-
- if (sec != 0)
- {
- rate = (theEp->numBytesIn / sec) / 1024;
- fprintf(stdout, "Transfer rate - %ld KBytes/Sec. \n", rate);
- }
- else if (msec != 0)
- {
- rate = (theEp->numBytesIn *1000 / msec) / 1024;
- fprintf(stdout, "Transfer rate - %ld KBytes/Sec. \n", rate);
- }
- break;
-
- case T_IDLE: // we're either really idle, or the we've processed a disconnect event
- // if we processed a disconnect event then the busy flag for the ep would still be set
- if (TstEPBusyFlag(theEp->flags)) // we're we previously connected
- {
- ClrPassconFlag(theEp->flags); // clear the flag so that we can accept a new connection
- ClrOrdDisconFlag(theEp->flags);
-
- ClrTempFileFlag(theEp->flags);
- ClrPassconFlag(theEp->flags);
-
- if (TstTempFileFlag(theEp->flags))
- // is there an open spool file associated with this endpoint
- gFRefNumToClose = theEp->fRefNum; // set the global to have this file closed
- // note that this method of signalling for a file to
- // get closed is a quick and dirty method and assumes th
- // that only one file at a time is being processed here.
-
- #if HANDOFF_EP
- // in order to re-use a handoff endpoint, it must be unbound. Unbinding the
- // endpoint clears the connection information that allows to to know which
- // endpoint, incoming PAP data is routed to.
- if (theEp->ep != gEp.ep)
- {
- OTUnbind(theEp->ep);
-
- }
- #else
- // set flag so that we will check the status
- SetCheckOptFlag(gFlags);
- // indicate that we are no longer busy
- ClrEPBusyFlag(theEp->flags);
- SetStatusIdleFlag(gFlags);
-
- #endif
- }
- break;
-
- }
-
-
- err1 = CheckFileToClose();
- if (err1 != noErr)
- fprintf(stdout, "\n\nCheckFileToClose error - %ld.\n", err1);
-
- if (TstCheckOptFlag(gFlags))
- {
-
- if (EndpointsAllBusy())
- {
- if (TstStatusBusyFlag(gFlags) == false)
- {
- BeginSetServerStatusOption(gEp.ep, kSetBusyStr);
- SetStatusBusyFlag(gFlags);
- }
- }
- else
- {
- if (TstStatusBusyFlag(gFlags) == true)
- {
- BeginSetServerStatusOption(gEp.ep, kSetIdleStr);
- ClrStatusBusyFlag(gFlags);
- }
- }
- ClrCheckOptFlag(gFlags);
- }
-
-
- }
-
- }
-
- /* Do the right thing for an event. Determine what kind of event it is, and
- ** call the appropriate routines. */
-
- void DoEvent(EventRecord *event)
- {
- Point pt;
- char key;
-
- switch(event->what)
- {
-
- case nullEvent:
- case mouseDown:
- case activateEvt:
- case updateEvt:
- case kHighLevelEvent:
- break;
-
- case autoKey:
- case keyDown:
- key = event->message & charCodeMask;
- switch (key)
- {
- case 'q':
- case 'Q':
- if (event->modifiers & cmdKey)
- gDone = true;
- break;
- }
- break;
-
- case osEvt:
- switch ((event->message >> 24) & 0xFF)
- {
- /* Must logical and with 0xFF to get only low byte. */
- /* High byte of message. */
-
- case mouseMovedMessage:
- break;
-
- case suspendResumeMessage:
- /* Suspend/resume is also an activate/deactivate. */
- if ((event->message) & resumeFlag)
- ClrInBackGndFlag(gFlags); // process has come to the foreground
- else
- SetInBackGndFlag(gFlags); // process has gone into background
- break;
- }
- break;
-
- case diskEvt:
- if (HiWord(event->message) != noErr)
- {
- SetPt(&pt, kDILeft, kDITop);
- DIBadMount(pt, event->message);
- } /* It is not a bad idea to at least call DIBadMount in response to */
- break; /* a diskEvt, so that the user can format a floppy. */
- }
-
- }
-
-
- /*******************************************************************************
- ** DoBind
- ** Implements the option to set the qlen field and to bing with an nbpName
- ** by setting the nbpName field with a pointer to an entity name.
- ** If nbpName is not nil, you must also set the nbpNameLen to the size of the
- ** nbpName field. Note, nbpName is not a pascal nor a C string.
- ********************************************************************************/
-
- OSStatus DoBind(EndpointRef ep, UInt8 socket, UInt8 type, OTQLen qlen,
- char *nbpName, UInt32 nbpNameLen)
- {
- TBind req, ret;
- OSStatus err = kOTNoError;
- DDPNBPAddress addr;
-
-
- // init the DDPAddress variable
- if (nbpName == nil) // are we registering with no nbp name
- {
- addr.fAddressType = AF_ATALK_DDP; // set the address type
- req.addr.len = kDDPAddressLength;
- }
- else
- {
- addr.fAddressType = AF_ATALK_DDPNBP; // registering with an nbp name
- // copy the name to the name buffer
- BlockMove(nbpName, &addr.fNBPNameBuffer, nbpNameLen);
- // set the request length to include the name len
- req.addr.len = kDDPAddressLength + nbpNameLen;
- }
-
- addr.fNetwork = 0;
- addr.fNodeID = 0;
- addr.fSocket = socket;
- addr.fDDPType = type;
-
- // set up the request
- req.addr.buf = (UInt8*)&addr;
- req.qlen = qlen;
-
- // set up the response
- ret.addr.buf = (UInt8*)&addr;
- ret.addr.maxlen = sizeof(addr);
-
- fprintf(stderr, "Doing Bind\n");
-
- //
- // Try to bind
- //
- err = OTBind(ep, &req, &ret);
-
- if ( err != kOTNoError )
- {
- fprintf(stderr, "PAPSample: DoBind returns error %ld\n", err);
- return err;
- }
-
- fprintf(stderr, "Bound address = ");
- ShowDDPAddress((DDPAddress*)&addr);
- fprintf(stderr, "\n");
- fprintf(stderr, "Bound queue len is %ld\n", ret.qlen);
-
- fprintf(stderr, "After Bind, ");
- ShowEndpointState(ep, "");
-
- return err;
- }
-
-
-
- /*******************************************************************************
- ** ActivatePAPEndpoint
- **
- ********************************************************************************/
-
- OSStatus ActivatePAPEndpoint(MyEndpointRef *myEp)
- {
- OSStatus err = kOTNoError;
-
- //
- // Create a PAP endpoint
- // Open listener, using the tilisten module to make
- // listen/accept/disconnect processing much simpler.
- //
- myEp->ep = OTOpenEndpoint(OTCreateConfiguration("tilisten, pap"), 0, NULL, &err);
-
- if ( myEp->ep == NULL || err != kOTNoError )
- {
- myEp->ep = NULL;
-
- if (err == kOTNoError)
- err = memFullErr;
-
- fprintf(stderr,"ERROR: OpenEndpoint(\"pap\") failed with %ld\n", err);
- }
- else
- {
- SetEPActiveFlag(myEp->flags);
- }
-
- /*-------------------------------------------------------------------------
- Enable self send
- have to do this before we set the endpoint into async mode.
- ------------------------------------------------------------------------- */
- if (err == kOTNoError)
- {
- err = DoNegotiateSelfSendOption(myEp->ep, 1);
-
- if (err <= kOTNoError)
- {
- fprintf(stderr, "error negotiating selfsend on main endpoint\n");
- err = kOTNoError; // don't let this stop the app.
- }
- else
- {
- fprintf(stderr, "selfsend enabled\n");
- if (err == 0)
- fprintf(stderr, "selfsend was previously off\n");
- else
- fprintf(stderr, "selfsend was previously on\n");
- }
- }
-
- #if HANDOFF_EP
- #else
- // don't need EOM option
- if (err == kOTNoError)
- {
-
- // turn on the EOM option
- err = DoNegotiateEOMOption(myEp->ep, true);
- if (err != kOTNoError)
- {
- ClrEOMOnFlag(myEp->flags);
- fprintf(stderr, "\n\nError setting EOM option!\n");
- }
- else
- {
- SetEOMOnFlag(myEp->flags);
- }
- }
- #endif
-
- if (err == kOTNoError)
- {
- //
- // Install notifier we're going to use for testing - we do this before
- // binding - at this point, we're still synchronous
- //
- err = OTInstallNotifier(myEp->ep, EventHandler, (void*)myEp);
- if ( err != kOTNoError )
- {
- fprintf(stderr, "ERROR: InstallNotifier() failed with %ld\n for server endpoint", err);
- }
- }
-
- if (err == kOTNoError)
- {
-
- /*-------------------------------------------------------------------------
- Prepare to Bind the endpoint by getting the NBP Name
- ------------------------------------------------------------------------- */
-
- /*-------------------------------------------------------------------------
- Bind the endpoint endpoint.
- ------------------------------------------------------------------------- */
-
- err = DoBind(myEp->ep, kDynamicSocket, kATPType, 2, (char*)gServerNBPNameStr, clen((char*)gServerNBPNameStr));
- if ( err != kOTNoError )
- {
- fprintf(stderr, "PAPSample: bind of server endpoint failed.\n");
- }
- else
- {
- SetEPBoundFlag(myEp->flags);
- OTSetAsynchronous(myEp->ep);
- }
- }
-
- /*-------------------------------------------------------------------------
- Set the server status string
- ------------------------------------------------------------------------- */
- if (err == kOTNoError)
- BeginSetServerStatusOption(myEp->ep, kSetIdleStr);
-
-
-
- return err;
- }
-
- /*******************************************************************************
- ** InitMyEndpointRef function - zero out the MyEndpointRef structure
- ** Course we could use the memset function here.
- ********************************************************************************/
-
- OSStatus InitMyEndpointRef(MyEndpointRef *myEp)
- {
- myEp->ep = nil;
- myEp->flags = 0;
- myEp->usedQ = OTAllocMem(sizeof(OTLIFO));
- if (myEp->usedQ == nil)
- return memFullErr;
-
- myEp->usedQ->fHead = nil; // no packets with this endpoint.
-
- return kOTNoError;
- }
-
-
- OSStatus InitPAPBuffers(void)
- {
- PacketPtr packetPtr;
- OSStatus err = kOTNoError;
- short i;
-
- // allocate memory for the freeQ
- gFreeQ = OTAllocMem(sizeof(OTLIFO));
- if (gFreeQ == nil)
- return memFullErr;
-
- /* set up the free queue */
- gFreeQ->fHead = nil;
-
- // allocate a temp buffer to be used when packet data overlaps.
- gTempPackPtr = OTAllocMem(sizeof(PacketBuffer) + kPAPDataSize);
- if (gTempPackPtr == nil)
- err = memFullErr;
-
- /* enqueue the packet buffer records to the free queue */
- for (i=0; (i<kNumBuffers) && (err == kOTNoError); i++)
- {
- // before calling OTAllocMem, we must have already have called
- // InitOpenTransport
-
- packetPtr = OTAllocMem(sizeof(PacketBuffer));
- if (packetPtr != nil)
- {
- packetPtr->flags = 0;
- packetPtr->fLink.fNext = nil;
- OTLIFOEnqueue(gFreeQ, &(packetPtr->fLink)); // first field is fLink field
-
- }
- else
- err = memFullErr;
- }
-
- if (err == kOTNoError)
- {
- /* show that the buffers have been init'd */
- SetBufsInitdFlag(gFlags);
-
- /* note that we don't need to worry about holding memory in the
- presence of VM. The notifier routine will be called at
- deferred task time when it is safe to page memory
- */
-
- }
- else
- {
- fprintf(stderr, "\n\nError allocating receive buffers!\n");
- fprintf(stderr, "\nBye Bye.\n");
- }
-
- return(err);
-
- }
-
-
-
- /*******************************************************************************
- ** Initialize OpenTransport and call DoTest function
- ********************************************************************************/
- OSStatus InitPAPServerStuff(void)
- {
- OSStatus err = kOTNoError;
- UInt32 growAmt, selection;
- UInt32 i;
- char mystr[255];
-
- // register ourselves with OT
- OTRegisterAsClient((OTClientName) "PAPServerSample", nil);
-
- // ask whether to alter current options
- fprintf(stdout, "\nDo you want to change the current options?");
- fprintf(stdout, "\n Options to change 1. SetMemoryLimits");
- fprintf(stdout, "\n 2. Dump packets");
- selection = GetYesNoOption();
- if (selection == kQuitTest)
- err = -1;
- else if (selection == kAcceptOption)
- {
- // ask whether to use the set memory limits option or not
- fprintf(stdout, "\nDo you want to set memory limits?");
- selection = GetYesNoOption();
-
- if (selection == kQuitTest)
- err = -1;
- else if (selection == kAcceptOption)
- {
- fprintf(stderr, "How much memory to grow heap ?\n");
- if (gets(mystr) != 0)
- {
- StringToNum(c2pstr(mystr), (long*)&growAmt);
- OTSetMemoryLimits(growAmt, 0);
-
- }
- }
-
- if (err == kOTNoError)
- {
- // ask whether to use the set memory limits option or not
- fprintf(stdout, "\nDo you want to just dump packets?");
- selection = GetYesNoOption();
- if (selection == kQuitTest)
- err = -1;
- else if (selection == kAcceptOption)
- {
- SetdumpPktsFlag(gFlags);
- }
- }
- }
-
- if (err == kOTNoError)
- {
-
- // load in the various strings
- GetIndString((unsigned char*)&gIdleStr, kServerStrID, kIdleStrID);
- GetIndString((unsigned char*)&gBusyStr, kServerStrID, kBusyStrID);
- GetIndString((unsigned char*)&gServerNBPNameStr, kServerStrID, kServerNBPStrID);
- // covert each string to c
- p2c(gIdleStr);
- p2c(gBusyStr);
- p2c(gServerNBPNameStr);
-
- // initialize the endpoint ref
- err = InitMyEndpointRef(&gEp);
- }
-
- if (err == kOTNoError)
- {
- #if HANDOFF_EP
- for (i = 0; (i < kMaxHandoffEPs) && (err == kOTNoError) ; i++)
- err = InitMyEndpointRef(&gHandoffEp[i]);
- #endif
- }
-
- if (err == kOTNoError)
- {
- //
- // Initialize the buffers
- //
- err = InitPAPBuffers();
- }
-
-
- if (err == kOTNoError)
- {
- //
- // Init the server endpoint
- //
- err = ActivatePAPEndpoint(&gEp);
- }
-
- #if HANDOFF_EP
- if (err == kOTNoError)
- {
- //
- // Init the handoff endpoint
- //
- for (i = 0; (i < kMaxHandoffEPs) && (err == kOTNoError); i++)
- gHandoffEp[i].ep = OTOpenEndpoint(OTCreateConfiguration(kPAPName), (OTOpenFlags)NULL, NULL, &err);
-
- if (err != kOTNoError)
- {
- fprintf(stderr, "\n\nError opening the handoff endpoint!\n");
- fprintf(stderr, "\nBye Bye.\n");
- }
- else
- {
- for (i = 0; (i < kMaxHandoffEPs) && (err == kOTNoError); i++)
- {
- SetEPActiveFlag(gHandoffEp[i].flags);
- // turn on the EOM option
- err = DoNegotiateEOMOption(gHandoffEp[i].ep, true);
- if (err != kOTNoError)
- {
- ClrEOMOnFlag(gHandoffEp[i].flags);
- fprintf(stderr, "\n\nError setting EOM option!\n");
- }
- else
- {
- SetEOMOnFlag(gHandoffEp[i].flags);
- }
- }
- }
- }
-
-
- if (err == kOTNoError)
- {
- for (i = 0; (i < kMaxHandoffEPs) && (err == kOTNoError); i++)
- {
- err = OTInstallNotifier(gHandoffEp[i].ep, EventHandler, (void*)&gHandoffEp[i]);
- if ( err != kOTNoError )
- {
- fprintf(stderr, "ERROR: InstallNotifier() failed with %ld\n for handoff endpoint", err);
- }
- else
- OTSetAsynchronous(gHandoffEp[i].ep);
- }
-
- }
- #endif // HANDOFF_EP
-
- return err;
-
- }
-
-
- /*******************************************************************************
- ** ReleasePAPMemory
- ********************************************************************************/
-
- void ReleasePAPMemory(void)
- {
- PacketPtr packetPtr;
- OTLIFO *otLIFOPtr;
- short i;
-
- if (gTempPackPtr)
- OTFreeMem(gTempPackPtr);
-
- // first release the freeQ memory
- otLIFOPtr = gFreeQ;
- packetPtr = (PacketPtr)OTLIFODequeue(otLIFOPtr);
-
- while (packetPtr != nil) // while the queue is not empty
- {
- // free the packetbuffer
- OTFreeMem(packetPtr);
- packetPtr = (PacketPtr)OTLIFODequeue(otLIFOPtr);
- }
-
- #if HANDOFF_EP
- for (i = 0; i < kMaxHandoffEPs; i++) //
- {
- otLIFOPtr = gHandoffEp[i].usedQ;
- #else
- otLIFOPtr = gEp.usedQ;
- #endif
- if (otLIFOPtr->fHead)
- fprintf(stderr, "Am releasing buffer from the used queue.\n\n");
-
- packetPtr = (PacketPtr)OTLIFODequeue(otLIFOPtr);
-
- while (packetPtr != nil) // while the queue is not empty
- {
- // free the packetbuffer
- OTFreeMem(packetPtr);
- packetPtr = (PacketPtr)OTLIFODequeue(otLIFOPtr);
- }
-
- #if HANDOFF_EP
- }
- #endif
-
- OTFreeMem(gFreeQ);
-
- }
-
- /*******************************************************************************
- ** Close endpoints, and OpenTransport
- ********************************************************************************/
-
- void ClosePAPServerStuff(void)
- {
-
- short i;
-
- if (gEp.ep)
- OTSetSynchronous(gEp.ep);
-
- // note that we don't check whether the endpoint is still connected. Since
- // we are leving anyway, let the UnBind call clear things up. If we did do a
- // disconnect here, we would meed to also implement a timer mechanism. so that
- // we didn't get hung awaiting a DisconnectComplete event that might not come.
-
- #if HANDOFF_EP
- for (i = 0; i < kMaxHandoffEPs; i++)
- {
-
- if (gHandoffEp[i].ep)
- OTSetSynchronous(gHandoffEp[i].ep);
-
- if (TstEPBoundFlag(gHandoffEp[i].flags)) // is the handoff endpoint bound
- OTUnbind(gHandoffEp[i].ep); // unbind the endpoint
-
- if (gHandoffEp[i].usedQ != nil) // free allocated memory with usedQ.
- OTFreeMem(gHandoffEp[i].usedQ);
-
- if (TstEPActiveFlag(gHandoffEp[i].flags)) // is the handoff endpoint open
- OTCloseProvider(gHandoffEp[i].ep); // close the endpoint
-
- }
-
- #endif
-
- if (TstEPBoundFlag(gEp.flags)) // is the server endpoint bound
- OTUnbind(gEp.ep); // unbind the endpoint
-
- if (gEp.usedQ != nil) // free allocated memory with usedQ.
- OTFreeMem(gEp.usedQ);
-
- if (TstEPActiveFlag(gEp.flags)) // is the server endpoint open
- OTCloseProvider(gEp.ep); // close the endpoint
-
- // ReleasePAPMemory(); // release memory before OT goes away
- // not really necessary since we are just going to
- // exit after this.
-
- if (gFreeQ != nil)
- OTFreeMem(gFreeQ);
-
- if (TstOTActiveFlag(gFlags)) // is OpenTransport active
- CloseOpenTransport(); // shutdown OT services
-
- }
-
- //
- // NetInit:
- //
- // This routine does various networking related startup tasks:
- //
- // (1) it does InitOpenTransport
- // (2) it records the OT version for us.
- //
- // result - true - OpenTransport init'd and the correct version is present
- // false - problem opening OT or OT version not correct
- //
- static Boolean NetInit()
- {
- OSStatus err;
-
- err = Gestalt(gOTVersionSelector, (long*) &gOTVersion);
- if (err || (gOTVersion < kOTVersion111))
- {
- fprintf(stderr, "Please install Open Transport 1.1.1 or later");
- return false;
- }
-
- err = InitOpenTransport();
- if (err)
- {
- fprintf(stderr, "NetInit: InitOpenTransport error %d", err);
- return false;
- }
- return true;
- }
-
-
- /*******************************************************************************
- ** main function
- ********************************************************************************/
-
- main(void)
- {
- OSStatus osstatus;
-
- InitGraf(&qd.thePort); // initialize quickdraw so we can use regions
-
- fprintf(stderr, "PAPServerSample showing implementation of PAP server.\n\n");
-
- // init the flags variable
- gFlags = 0;
-
- #if DO_DEBUG_LOG
- DebugStr("\p doing log;dx;log papserver;g");
- #endif
-
- if (NetInit() == false)
- return 0;
-
- //
- // Initialize the OT and the global Endpoints
- //
- osstatus = InitPAPServerStuff();
-
- if (osstatus == kOTNoError)
- {
-
-
- //
- // Run the PAPServer code
- //
- DoServer();
- //
- }
-
- //
- // Close things down
- //
- ClosePAPServerStuff();
-
- CheckFileToClose();
-
- fprintf(stderr, "\n\nDone\n");
-
- return 0;
- }
-
- void DoValueBreak(long value, const char* message)
- {
- static short sDoErrorBreak = 0;
-
- {
- Str255 s,
- n = "\p";
-
- s[0] = strlen(message);
- BlockMoveData(message,&s[1],s[0]);
- if (value < 0)
- {
- s[0] += 1;
- s[s[0]] = '-';
- value = -value;
- }
- while (value)
- {
- if (n[0])
- BlockMoveData(&n[1],&n[2],n[0]);
- n[0]++;
- n[1] = 48 + (value % 10);
- value /= 10;
- }
- BlockMoveData(&n[1],&s[s[0]+1],n[0]);
- s[0] += n[0];
-
- sDoErrorBreak++;
- {
- short cnt = sDoErrorBreak;
-
- s[0]++;
- s[s[0]] = ',';
- s[0]++;
- s[s[0]] = ' ';
- n[0] = 0;
- while (cnt)
- {
- if (n[0])
- BlockMoveData(&n[1],&n[2],n[0]);
- n[0]++;
- n[1] = 48 + (cnt % 10);
- cnt /= 10;
- }
- BlockMoveData(&n[1],&s[s[0]+1],n[0]);
- s[0] += n[0];
- }
- DebugStr(s);
- }
- }
-
-
- OSStatus BeginSetServerStatusOption(EndpointRef ep, UInt16 whichStr)
- {
- OSStatus err;
- unsigned char *in = "\p._in";
-
- if (whichStr == kSetIdleStr)
- {
- err = DoSetServerStatusOption(ep, (char*)&gIdleStr);
- }
- else
- {
- err = DoSetServerStatusOption(ep, (char*)&gBusyStr);
- }
-
- if (err != kOTNoError)
- {
- fprintf(stderr, "ServerStatus option call failed\n");
- fprintf(stderr, "however, this will not keep the server from running\n");
- err = kOTNoError;
- }
-
- return err;
- }
-
-
- UInt32 GetYesNoOption(void)
- {
- UInt32 result;
- char selection[32];
- Boolean done;
-
- fprintf(stdout, "\n Enter Y - To accept option");
- fprintf(stdout, "\n Enter N - To decline option");
- fprintf(stdout, "\n Enter Q - To quit");
- fprintf(stdout, "\nYour selection -> ");
- fflush(stdout);
- done = false;
-
- do
- {
- if (gets(selection) != 0)
- {
- switch (selection[0])
- {
- case 'y':
- case 'Y':
- result = kAcceptOption;
- done = true;
- break;
-
- case 'n':
- case 'N':
- result = kDeclineOption;
- done = true;
- break;
-
- case 'q':
- case 'Q':
- result = kQuitTest;
- done = true;
- break;
-
- default:
- fprintf(stdout, "\nInvalid entry - %c, try again -> ", selection);
- fflush(stdout);
- break;
-
- }
- }
- } while (!done);
-
- fflush (stdout);
- return result;
- }
-
-
- #if HANDOFF_EP
- /*
- Iterate through the handoff endpoints and find one that doesn't have the busy flag
- set - return the pointer else return null
- */
- MyEndpointRef* FindFreeHandoffEp(void)
- {
- short i;
-
- for (i = 0; i < kMaxHandoffEPs; i++)
- {
- if (TstEPBusyFlag(gHandoffEp[i].flags) == false)
- return &gHandoffEp[i];
- }
-
- return nil;
- }
- #endif
-
- Boolean EndpointsAllBusy(void)
- {
- Boolean result = true;
- #if HANDOFF_EP
- short i;
-
- for (i = 0; (i < kMaxHandoffEPs) && (result == true); i++)
- {
- if (TstEPBusyFlag(gHandoffEp[i].flags) == false)
- result = false; // any endpoint not busy means that not all eps are busy
- }
-
- #else
- result = TstEPBusyFlag(gEp.flags);
-
- #endif
-
- return result;
- }